package org.benjamin.lending.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.digest.HmacUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.benjamin.lending.domain.config.ConfigBean;
import org.benjamin.lending.domain.entity.*;
import org.benjamin.lending.domain.trusteeship.RequestParameter;
import org.benjamin.lending.domain.trusteeship.SumapayBean;
import org.benjamin.lending.domain.trusteeship.SumapayList;
import org.benjamin.lending.repository.MemberIdentityRepository;
import org.benjamin.lending.repository.MemberInfoRepository;
import org.benjamin.lending.repository.TrusteeshipRequestRepository;
import org.benjamin.lending.service.RechargeService;
import org.benjamin.lending.service.TrusteeshipService;
import org.benjamin.lending.trusteeship.sumapay.AccountManagerOperation;
import org.benjamin.lending.trusteeship.sumapay.RealNameAuthOperation;
import org.benjamin.lending.trusteeship.sumapay.RechargeOperation;
import org.springframework.beans.factory.annotation.Autowired;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.annotation.Transient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

@Service("trusteeshipService")
@Transactional
public class SumapayService implements TrusteeshipService {

    private final String MERCHANT_CODE = "32132132";

    private final String SECRET_KEY = "dsadsadsadsa";


    private final Logger logger = LogManager.getLogger();

    @Autowired
    private MemberInfoRepository memberInfoRepository;
    
    @Autowired
    private MemberIdentityRepository memberIdentityRepository;

    @Autowired
    private TrusteeshipRequestRepository trusheeshipRequestRepository;

    @Autowired
    private RechargeService rechargeService;
    
    @Autowired
    private RechargeOperation sumaplayRechargeOperation;

    @Autowired
    @Qualifier("sumapayAccountManagerOperation")
    private AccountManagerOperation accountManagerOperation;

    @Autowired
    private RealNameAuthOperation realNameAuthOperation;

    @Autowired
    private BasicOperation basicOperation;

    @Override
    public RequestParameter accountManager(String username) throws RuntimeException {
        RequestParameter requestParameter = this.accountManagerOperation.request(username,null);
        return requestParameter;
    }

    @Override
    public boolean realNameAuthRequest(String username, String idNumber, String realName) throws RuntimeException {
        Map<String,Object> parameterMap = new HashMap<String, Object>();
        parameterMap.put("realName",realName);
        parameterMap.put("idNumber",idNumber);
        RequestParameter parameter = this.realNameAuthOperation.request(username,parameterMap);
        TrusteeshipRequest trusteeshipRequest = this.trusheeshipRequestRepository.findOne(parameter.getRequestMap().get("requestId").toString());
        try {
            String resultString = this.basicOperation.sendHttpClient(parameter.getUrl(),parameter.getRequestMap(),"GBK");
            Map<String,Object> responseMap = new ObjectMapper().readValue(resultString,Map.class);
            this.realNameAuthResponse(trusteeshipRequest,responseMap);
            return true;
        } catch (IOException e) {
            logger.error(e.getMessage(),e);
            throw new IllegalArgumentException("发送信息出现异常："+e.getMessage());
        }
    }

    public void realNameAuthResponse(TrusteeshipRequest trusteeshipRequest,Map<String,Object> responseMap){
        this.realNameAuthOperation.response(trusteeshipRequest,responseMap);
    }

    /**
     * 快速充值通道
     *
     * @param username 充值用户
     * @param amount   充值金额
     * @param createIp 请求用户的IP地址
     * @return
     * @throws RuntimeException
     */
    @Override
    public RequestParameter simpleRecharge(String username, BigDecimal amount, String createIp) throws RuntimeException {

        Map<String, Object> httpRequestParam = new HashMap<String, Object>();
        httpRequestParam.put("amount", amount);

        Map<String, Object> requestMap = this.buildRequestAndResult();
        requestMap.put("userIdIdentity", this.buildUserIdentity(username));
        requestMap.put("sum", amount);
        requestMap.put("payType", 2);
        try {
            List<SumapayList> sumapayLists = new ArrayList<SumapayList>();
            sumapayLists.add(new SumapayList(0, requestMap.get("userIdIdentity").toString(), 0, amount, 0));
            this.buildSubledgerList(requestMap, sumapayLists);
            requestMap.put("signature", this.buildSignature(requestMap, SumapayBean.SIMPLE_RECHARGE));
            RequestParameter requestParameter = new RequestParameter(requestMap, SumapayBean.DOMAIN_NAME + SumapayBean.SIMPLA_RECHARGE_URL);
            logger.info("封装请求参数，下一步创建充值记录，用来充值交易跟踪凭证");
            MemberInfo memberInfo = this.memberInfoRepository.findByUsername(username);
            RechargeLog rechargeLog = this.rechargeService.createRechargeLog(memberInfo, "", amount, BigDecimal.ZERO, createIp);
            logger.info("充值记录生成成功：记录编号：{}", rechargeLog.getId());
            TrusteeshipRequest trusteeshipRequest = this.saveRequestParameter(requestParameter, memberInfo, TrusteeshipType.recharge, rechargeLog.getId(), httpRequestParam);
            logger.info("保存丰付快捷充值交易信息记录，记录单号：{}", trusteeshipRequest.getId());
            return requestParameter;
        } catch (JsonProcessingException e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    @Override
    public RequestParameter bankRecharge(String username, BigDecimal amount, String bankCode, String createIp) throws RuntimeException {
    	Map<String,Object> parameterMap = new HashMap<String, Object>();
    	parameterMap.put("amount", amount);
    	parameterMap.put("bankCode", bankCode);
    	parameterMap.put("createIp", createIp);
        return this.sumaplayRechargeOperation.request(username, parameterMap);
    }

    /**
     * 相应处理充值操作
     *
     * @param trusteeshipRequest
     */
    public void responseRecharge(TrusteeshipRequest trusteeshipRequest, Map<String, Object> responseMap, String createIp) {
        Integer rel = trusteeshipRequest.getRel();
        String result = responseMap.get("result").toString();
        if (StringUtils.equalsAny(result, "00000","00001")) {
            this.rechargeService.rechargeSuccess(rel, createIp);
        } else {
            this.rechargeService.rechargeFail(rel, createIp);
        }
    }
    
    


    @Override
	public void replaceBankCrad(String reason, MemberInfo memberInfo) {
    	Map<String,Object> requestMap = this.buildRequestAndResult();
    	MemberIdentity memberIdentity = this.memberIdentityRepository.findOne(memberInfo.getId());
    	requestMap.put("userIdIdentity", this.buildUserIdentity(memberInfo.getUsername()));
    	requestMap.put("userName", memberIdentity.getRealName());
    	requestMap.put("idNumber", memberIdentity.getIdentityNumber());
    	requestMap.put("telephone", memberInfo.getMobile());
    	requestMap.put("email", memberInfo.getEmail());
    	requestMap.put("reason", reason);
    	String signater = this.buildSignature(requestMap, SumapayBean.REPLACE_BANLCARD_RULES);
    	requestMap.put("signater", signater);
    	
	}

	@Override
    public String responseAsyn(Map<String, Object> responseMap, String createIp) {
        String requestId = responseMap.get("requestId").toString();
        TrusteeshipRequest trusteeshipRequest = this.trusheeshipRequestRepository.findOne(requestId);
        Assert.notNull(trusteeshipRequest,"当前requestId无法查询到对象");
        switch (trusteeshipRequest.getType()) {
            case recharge:
            	sumaplayRechargeOperation.response(trusteeshipRequest,responseMap);
                break;
		default:
			break;
        }
        return null;
    }


    /**
     * 初始默认requestId和商户编号参数
     *
     * @return
     */
    private Map<String, Object> buildRequest() {
        Map<String, Object> requestMap = new HashMap<String, Object>();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String requestId = simpleDateFormat.format(System.currentTimeMillis());
        requestId = requestId + RandomStringUtils.randomNumeric(4);
        requestMap.put("requestId", requestId);
        requestMap.put("merchantCode", MERCHANT_CODE);
        return requestMap;
    }

    private Map<String, Object> buildRequestAndResult() {
        Map<String, Object> requestMap = this.buildRequest();
        this.defaultRequestUrlParam(requestMap);
        return requestMap;
    }

    private void defaultRequestUrlParam(Map<String, Object> requestMap) {
        requestMap.put("successResultUrl", ConfigBean.getServerName() + "/trusteeship/success");
        requestMap.put("failResultUrl", ConfigBean.getServerName() + "/trusteeship/fail");
        requestMap.put("noticeUrl", ConfigBean.getServerName() + "/trusteeship/notice");
    }

    private void buildSubledgerList(Map<String, Object> requestmap, List<SumapayList> sumapayLists) throws JsonProcessingException {
        String subledgerList = new ObjectMapper().writeValueAsString(sumapayLists);
        requestmap.put("subledgerList", subledgerList);
    }

    public String buildUserIdentity(String username) {
        return "fnp2p_" + username.trim();
    }

    public String buildSignature(Map<String, Object> requestMap, String... keys) {
        StringBuffer stringBuffer = new StringBuffer();
        logger.info("签名加密的要求参数:{}", keys.toString());
        for (String key : keys) {
            Object temp = requestMap.get(key);
            if (temp != null) {
                stringBuffer.append(temp);
            }
        }
        String valueToDigest = stringBuffer.toString();
        logger.info("签名参数明文：{}", valueToDigest);
        return HmacUtils.hmacMd5Hex(SECRET_KEY, valueToDigest);
    }

    private void saveRequestParameter(RequestParameter requestParmeter, MemberInfo memberInfo) throws JsonProcessingException {
        TrusteeshipRequest request = new TrusteeshipRequest();
        request.setId(requestParmeter.getRequestMap().get("requestId").toString());
        request.setType(TrusteeshipType.accountManager);
        request.setTid(1);
        request.setUid(memberInfo.getId());
        request.setBid(0);
        request.setRel(0);
        request.setUrl(requestParmeter.getUrl());
        logger.info("封装参数进行序列化成JSON格式");
        String packData = new ObjectMapper().writeValueAsString(requestParmeter.getRequestMap());
        request.setPackData(packData);
        request.setCreateTime(new Timestamp(System.currentTimeMillis()));
        this.trusheeshipRequestRepository.save(request);
    }

    private TrusteeshipRequest saveRequestParameter(RequestParameter requestParameter, MemberInfo memberInfo, TrusteeshipType trusteeshipType, Integer rel, Map<String, Object> httpRequestParam) throws JsonProcessingException {
        TrusteeshipRequest request = new TrusteeshipRequest();
        request.setId(requestParameter.getRequestMap().get("requestId").toString());
        request.setType(trusteeshipType);
        request.setTid(1);
        request.setUid(memberInfo.getId());
        request.setBid(0);
        request.setRel(rel);
        request.setOrigData(new ObjectMapper().writeValueAsString(httpRequestParam));
        request.setStatus(RequestStatus.SENDING);
        request.setUrl(requestParameter.getUrl());
        logger.info("封装参数进行序列化成JSON格式");
        String packData = new ObjectMapper().writeValueAsString(requestParameter.getRequestMap());
        request.setPackData(packData);
        request.setCreateTime(new Timestamp(System.currentTimeMillis()));
        logger.info("当前丰付请求参数长度为：{}", request.getPackData().length());
        if (request.getPackData().length() >= 255) {
            logger.info("超出数据库保存上线！");
        }
        this.trusheeshipRequestRepository.save(request);
        return request;
    }

    
}
